#include <objbase.h>
#include <d3dcompiler.h>

#include "WindowsApplication.hpp"

#include "D3d12GraphicsManager.hpp"

using namespace My;

namespace My
{
	extern IApplication* g_pApp;

	template<class T>
	inline void SafeRelease(T** ppInterfaceToRelease)
	{
		if (*ppInterfaceToRelease == nullptr) return;

		(*ppInterfaceToRelease)->Release();

		(*ppInterfaceToRelease) = nullptr;
	}


	static void GetHardwareAdapter(IDXGIFactory4* pFactory, IDXGIAdapter1** ppAdapter)
	{
		IDXGIAdapter1* pAdapter = nullptr;
		*ppAdapter = nullptr;

		// 遍历系统中的DXGI适配器，寻找支持Direct3D 12的硬件适配器。
		// 忽略软件渲染适配器，只选择支持特定Direct3D功能的硬件适配器。
		for (UINT adapterIndex = 0; 
			DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &pAdapter);
			adapterIndex++)
		{
			DXGI_ADAPTER_DESC1 desc;
			pAdapter->GetDesc1(&desc);

			// 不要选择基本渲染驱动程序适配器
			if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
				continue;

			// 检查适配器是否支持Direct3D 12，但尚未创建实际设备
			if (SUCCEEDED(D3D12CreateDevice(
				pAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr)))
				break;
		}
		*ppAdapter = pAdapter;
	}

	int D3d12GraphicsManager::Initialize()
	{
		int result = 0;

		//创建图形资源
		result = static_cast<int>(CreateGraphicsResources());

		return result;
	}

	void D3d12GraphicsManager::Finalize()
	{
		SafeRelease(&m_pDev);	// 释放D3D12设备
	}

	void D3d12GraphicsManager::Tick()
	{
		// nothing
	}

	HRESULT D3d12GraphicsManager::CreateRenderTarget()
	{
		HRESULT hr;

		// 描述并创建呈现目标视图 （render target view RTV） 描述符堆
		D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
		{
			rtvHeapDesc.NumDescriptors = kFrameCount;
			rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
			rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
			if (FAILED(hr = m_pDev->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_pRtvHeap))))
				return hr;
		}

		m_nRtvDescriptorSize 
			= m_pDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

		D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle 
			= m_pRtvHeap->GetCPUDescriptorHandleForHeapStart();
		

		// 为每个帧创建渲染目标视图
		for (uint32_t i = 0; i < kFrameCount; i++)
		{
			if(FAILED(hr = m_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&m_pRenderTargets[i]))))
				break;
			m_pDev->CreateRenderTargetView(m_pRenderTargets[i], nullptr, rtvHandle);
			rtvHandle.ptr += m_nRtvDescriptorSize;
		}

		return hr;
	}

	// 这是加载和准备着色器的函数
	HRESULT D3d12GraphicsManager::InitPipeline()
	{
		HRESULT hr;

		// 创建命令分配器
		if (FAILED(hr = m_pDev->CreateCommandAllocator(
			D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_pCommandAllocator))))
			return hr;

		ID3DBlob* error;
		{
			// 创建空的根签名
			D3D12_ROOT_SIGNATURE_DESC rsd;
			rsd.NumParameters = 0;
			rsd.pParameters = nullptr;
			rsd.NumStaticSamplers = 0;
			rsd.pStaticSamplers = nullptr;
			rsd.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;

			ID3DBlob* signature;
			if (FAILED(hr = D3D12SerializeRootSignature(
				&rsd, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)))
				return hr;

			if (FAILED(hr = m_pDev->CreateRootSignature(
				0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_pRootSignature))))
				return hr;
		}


		// 加载着色器
#if defined(_DEBUG)
		// 使用图形调试工具实现更好的着色器调试
		UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
		UINT compileFlags = 0;
#endif

		// 编译顶点和像素着色器
		ID3DBlob* vertexShader;
		hr = D3DCompileFromFile(
			L"simple.hlsl",
			nullptr,
			D3D_COMPILE_STANDARD_FILE_INCLUDE,
			"VSMain",
			"vs_5_0",
			compileFlags,
			0,
			&vertexShader,
			&error);
		if (error)
		{
			OutputDebugString((LPCTSTR)error->GetBufferPointer());
			error->Release();
			return hr;
		}		

		ID3DBlob* pixelShader;
		hr = D3DCompileFromFile(
			L"simple.hlsl",
			nullptr,
			D3D_COMPILE_STANDARD_FILE_INCLUDE,
			"PSMain",
			"ps_5_0",
			compileFlags,
			0,
			&pixelShader,
			&error);
		if (error)
		{
			OutputDebugString((LPCTSTR)error->GetBufferPointer());
			error->Release();
			return hr;
		}

		// 设置输入布局对象
		D3D12_INPUT_ELEMENT_DESC ied[] =
		{
			{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
			{"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
			{"TANGENT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
			{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
		};

		D3D12_RASTERIZER_DESC rd;
		{
			rd.FillMode = D3D12_FILL_MODE_SOLID;
			rd.CullMode = D3D12_CULL_MODE_BACK;
			rd.FrontCounterClockwise = FALSE;
			rd.DepthBias = 0;
			rd.DepthBiasClamp = 0.0f;
			rd.SlopeScaledDepthBias = 0.0f;
			rd.DepthClipEnable = TRUE;
			rd.MultisampleEnable = FALSE;
			rd.AntialiasedLineEnable = FALSE;
			rd.ForcedSampleCount = 0;
			rd.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
		}

		D3D12_BLEND_DESC bd;
		{
			bd.AlphaToCoverageEnable = FALSE;
			bd.IndependentBlendEnable = FALSE;
			bd.RenderTarget[0].BlendEnable = FALSE;
			bd.RenderTarget[0].LogicOpEnable = FALSE;
			bd.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
			bd.RenderTarget[0].DestBlend = D3D12_BLEND_ZERO;
			bd.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
			bd.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
			bd.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
			bd.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
			bd.RenderTarget[0].LogicOp = D3D12_LOGIC_OP_NOOP;
			bd.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
		}

		// 描述并创建图形管线状态对象 （pipeline state object,PSO）
		D3D12_GRAPHICS_PIPELINE_STATE_DESC psod = {};
		{
			psod.InputLayout = { ied, _countof(ied) };
			psod.pRootSignature = m_pRootSignature;			
			if(!reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer())) printf("VS");
			psod.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
			psod.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
			psod.RasterizerState = rd;
			psod.BlendState = bd;
			psod.DepthStencilState.DepthEnable = FALSE;
			psod.DepthStencilState.StencilEnable = FALSE;

			psod.SampleMask = UINT_MAX;
			psod.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
			psod.NumRenderTargets = 1;
			psod.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
			psod.SampleDesc.Count = 1;
		}

		if (FAILED(hr = m_pDev->CreateGraphicsPipelineState(&psod, IID_PPV_ARGS(&m_pPipelineState))))
			return hr;

		if (FAILED(hr = m_pDev->CreateCommandList(
			0,
			D3D12_COMMAND_LIST_TYPE_DIRECT,
			m_pCommandAllocator,
			m_pPipelineState,
			IID_PPV_ARGS(&m_pCommandList)))) 
			return hr;

		hr = m_pCommandList->Close();

		return hr;
	}

	HRESULT D3d12GraphicsManager::CreateGraphicsResources()
	{
		HRESULT hr;

		// 启用D3D12 调试层（调试模式下）
#if defined(_DEBUG)
		{			
			ID3D12Debug* pDebugController;
			if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDebugController))))
				pDebugController->EnableDebugLayer();
			pDebugController->Release();
		}
#endif

		IDXGIFactory4* pFactory;
		{
			// 创建DXGI工厂
			if (FAILED(hr = CreateDXGIFactory1(IID_PPV_ARGS(&pFactory))))
				return hr;

			// 初始化Direct3D12设备，首先尝试使用硬件适配器
			IDXGIAdapter1* pHardwareAdater;
			GetHardwareAdapter(pFactory, &pHardwareAdater);
			if (FAILED(hr = D3D12CreateDevice(pHardwareAdater,
				D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pDev))))
			{
				// 如果失败，则尝试使用WARP适配器
				IDXGIAdapter* pWarpAdapter;
				if (FAILED(hr = pFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter))))
				{
					SafeRelease(&pFactory);
					return hr;
				}

				if (FAILED(hr = D3D12CreateDevice(
					pWarpAdapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pDev))))
				{
					SafeRelease(&pFactory);
					return hr;
				}
			}
		}


		// 获取主窗口句柄
		HWND hWnd = reinterpret_cast<WindowsApplication*>(g_pApp)->GetMainWindow();

		// 创建命令队列
		{
			D3D12_COMMAND_QUEUE_DESC queueDesc = {};
			queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
			queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
			if (FAILED(hr = m_pDev->CreateCommandQueue(
				&queueDesc, IID_PPV_ARGS(&m_pCommandQueue))))
			{
				SafeRelease(&pFactory);
				return hr;
			}
		}

		// 创建一个结构体来保存有关交换链的信息
		DXGI_SWAP_CHAIN_DESC1 scd;
		{
			// 清理结构体
			ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC1));

			// 填写交换链描述结构
			scd.Width = g_pApp->GetConfiguration().screenWidth;
			scd.Height = g_pApp->GetConfiguration().screenHeight;
			scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;			// 使用 32-bit 颜色
			scd.Stereo = FALSE;
			scd.SampleDesc.Count = 1;							// 当 SwapEffect 设置为 DXGI_SWAP_EFFECT_FLIP_DISCARD 时
			scd.SampleDesc.Quality = 0;							// 不能使用多样本
			scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;	// 如何使用交换链
			scd.BufferCount = kFrameCount;						// 后台缓冲区计数
			scd.Scaling = DXGI_SCALING_STRETCH;
			scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;		// Win10之后的系统用 DXGI_SWAP_EFFECT_FLIP_DISCARD
																// Win10之前的系统用 DXGI_SWAP_EFFECT_DISCARD 
			scd.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
			scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;	// 允许全屏过渡
		}

		IDXGISwapChain1* pSwapChain;
		if (FAILED(hr = pFactory->CreateSwapChainForHwnd(
			m_pCommandQueue,							// 交换链需要队列，以便它可以强制刷新它
			hWnd,
			&scd,
			NULL,
			NULL,
			&pSwapChain
		)))
		{
			SafeRelease(&pFactory);
			return hr;
		}

		m_pSwapChain = reinterpret_cast<IDXGISwapChain3*>(pSwapChain);
		m_nFrameIndex = m_pSwapChain->GetCurrentBackBufferIndex();

		// 创建渲染目标
		hr = CreateRenderTarget();

		// 初始化渲染管线
		InitPipeline();

		return hr;
	}
}